package ru.aslanov.schedule.client;

import com.google.gwt.event.shared.HandlerRegistration;
import com.smartgwt.client.data.*;
import com.smartgwt.client.types.Autofit;
import com.smartgwt.client.types.OperatorId;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.types.VisibilityMode;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.util.SC;
import com.smartgwt.client.widgets.Button;
import com.smartgwt.client.widgets.Window;
import com.smartgwt.client.widgets.events.ClickEvent;
import com.smartgwt.client.widgets.events.ClickHandler;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.*;
import com.smartgwt.client.widgets.layout.*;
import com.smartgwt.client.widgets.layout.events.SectionHeaderClickEvent;
import com.smartgwt.client.widgets.layout.events.SectionHeaderClickHandler;
import ru.aslanov.schedule.client.ds.*;
import ru.aslanov.schedule.client.util.GUIUtil;
import ru.aslanov.schedule.client.util.MyAsyncCallback;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static ru.aslanov.schedule.client.i18n.I18nUtil.cnt;

/**
 * Created by IntelliJ IDEA.
 * Created: Feb 11, 2010 5:16:05 PM
 *
 * @author Sergey Aslanov
 */
public class GroupsPanel extends VLayout implements Invalidatable {
    private static final String DETAILS_SECTION_ID = "details";
    private DynamicForm form;
    private ListGrid schedulesGrid;
    private ListGrid groupsGrid;
    private Button newSchedule;
    private Button deleteSchedule;
    private Button saveButton;
    private Button newGroup;
    private Button deleteGroup;
    private VLayout schedulesPanel;
    private ScheduleUser scheduleUser;
    private Button setCalendarButton;
    private SectionStack sectionStack;

    public GroupsPanel(final ScheduleUser scheduleUser) {
        super();
        this.scheduleUser = scheduleUser;

        this.sectionStack = new SectionStack();
        this.sectionStack.setVisibilityMode(VisibilityMode.MULTIPLE);
        this.sectionStack.setWidth100();
        this.sectionStack.setHeight100();

        SectionStackSection groupsListSection = new SectionStackSection();
        groupsListSection.setID("groups");
        groupsListSection.setShowHeader(false);
        groupsListSection.setExpanded(true);
        groupsListSection.setCanCollapse(false);
        this.sectionStack.addSection(groupsListSection);

        final SectionStackSection groupDetailsSection = new SectionStackSection(cnt().groupDetailesTitle());
        groupDetailsSection.setID(GroupsPanel.DETAILS_SECTION_ID);
        groupDetailsSection.setExpanded(false);
        groupDetailsSection.setCanCollapse(true);
        this.sectionStack.addSection(groupDetailsSection);

        final VLayout gridPanel = new VLayout(10);
        gridPanel.setPadding(10);
        gridPanel.setWidth100();
        gridPanel.setHeight100();

        form = new DynamicForm();
        form.setGroupTitle(cnt().groupDetailesTitle());
        form.setNumCols(4);
        form.setDataSource(GroupsDS.getInstance(scheduleUser));
        form.setTitleOrientation(TitleOrientation.TOP);

        schedulesGrid = new ListGrid();
        schedulesGrid.setDataSource(ScheduleItemsDS.getInstance());
        schedulesGrid.setWidth(250);
        schedulesGrid.setHeight(150);
        schedulesGrid.setShowAllRecords(true);
        schedulesGrid.setAutoFitData(Autofit.BOTH);
        schedulesGrid.setCanEdit(true);
        schedulesGrid.setUseAllDataSourceFields(true);

        groupsGrid = new ListGrid() {
            @Override
            protected String getCellCSSText(ListGridRecord listGridRecord, int row, int col) {
                final String fieldName = getFieldName(col);
                if ((fieldName.equals("teacher1Key") || fieldName.equals("teacher2Key")) && scheduleUser.getCurrentTeacherKey() != null &&
                        scheduleUser.getCurrentTeacherKey().equals(listGridRecord.getAttribute(fieldName)))
                {
                    return "background-color:#ccffcc;";                        
                } else { 
                    return super.getCellCSSText(listGridRecord, row, col);
                }
            }
        };
                /*
                if (teacher1KeyFilter != null) {
                    String tempStr = "var advancedCriteria = {'_constructor':'AdvancedCriteria', 'operator':'or', 'criteria':" +
                            "[{'fieldName':'teacher1Key', 'operator':'equals', 'value':'" + teacher1KeyFilter + "' }, " +
                            "{ 'fieldName':'teacher2Key', 'operator':'equals', 'value':'" + teacher1KeyFilter + "'} ]}";
                    AdvancedCriteria advancedCriteria = new AdvancedCriteria(JSOHelper.eval(tempStr));
                    criteria.addCriteria(advancedCriteria);
                }
                */

        groupsGrid.setDataSource(GroupsDS.getInstance(scheduleUser));
        groupsGrid.setWidth100();
        groupsGrid.setHeight100();
        groupsGrid.setShowAllRecords(true);
        groupsGrid.setAutoFetchData(true);
        groupsGrid.setCanEdit(false);
        groupsGrid.setUseAllDataSourceFields(true);
        groupsGrid.setAutoFetchDisplayMap(true);
        groupsGrid.setShowFilterEditor(true);
        groupsGrid.setFilterOnKeypress(true);
        groupsGrid.addFilterEditorSubmitHandler(new FilterEditorSubmitHandler() {
            @Override
            public void onFilterEditorSubmit(FilterEditorSubmitEvent event) {
                final Criteria criteria = event.getCriteria();
                AdvancedCriteria fixedCriteria = new AdvancedCriteria(OperatorId.AND, new Criterion[]{});
                Map values = criteria.getValues();
                for (Object key : values.keySet()) {
                    final String fieldName = (String) key;
                    final String value = (String) values.get(key);
                    if (fieldName == null) continue;
                    if (fieldName.equals("teacher1Key")) {
                        fixedCriteria.addCriteria(new Criterion(OperatorId.OR, new Criterion[]{
                                new Criterion("teacher1Key", OperatorId.EQUALS, value),
                                new Criterion("teacher2Key", OperatorId.EQUALS, value)}));
                    } else {
                        fixedCriteria.addCriteria(new Criterion(fieldName, OperatorId.EQUALS, value));
                    }
                }
                event.cancel();
                groupsGrid.filterData(fixedCriteria);
                groupsGrid.setFilterEditorCriteria(criteria);
            }
        });

        ArrayList<ListGridField> listGridFields = new ArrayList<ListGridField>();

        GUIUtil.setupFKField(listGridFields, null, "locationKey", "encodedKey", "name", "name", LocationsDS.getInstance(scheduleUser), true, "locationName");

        schedulesGrid.setFields(listGridFields.toArray(new ListGridField[listGridFields.size()]));

        final HStack detailsPanel = new HStack(10);

        schedulesPanel = new VLayout(5);
        schedulesPanel.setVisible(false);
        //schedulesPanel.setWidth100();
        //schedulesPanel.setHeight100();

        schedulesPanel.addMember(schedulesGrid);

        HLayout schedulesButtonsPanel = new HLayout(5);
        schedulesButtonsPanel.setHeight(10);
        newSchedule = new Button(cnt().addButton());
        newSchedule.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                String groupKey = (String) form.getValue("encodedKey");
                if (groupKey != null) {
                    schedulesGrid.startEditingNew(Collections.singletonMap("group", groupKey));
                } else {
                    SC.say(cnt().saveGroupFirst());
                }
            }
        });
        schedulesButtonsPanel.addMember(newSchedule);

        deleteSchedule = new Button(cnt().removeButton());
        GUIUtil.addRemoveHandler(schedulesGrid, deleteSchedule, null);

        schedulesButtonsPanel.addMember(deleteSchedule);

        schedulesPanel.addMember(schedulesButtonsPanel);

        VLayout formPanel = new VLayout(5);
        formPanel.setPadding(10);
        formPanel.addMember(form);

        detailsPanel.addMember(formPanel);
        detailsPanel.addMember(schedulesPanel);

        final String saveNewTitle = cnt().saveNewGroup();
        saveButton = new Button(saveNewTitle);
        saveButton.setAutoFit(true);
        saveButton.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                form.saveData(new DSCallback() {
                    @Override
                    public void execute(DSResponse dsResponse, Object o, DSRequest dsRequest) {
                        groupsGrid.selectSingleRecord(dsResponse.getData()[0]);
                    }
                });

            }
        });
        formPanel.addMember(saveButton);


        gridPanel.addMember(groupsGrid);
        HLayout gridButtons = new HLayout(5);
        gridPanel.addMember(gridButtons);
        gridButtons.setWidth(20);

        newGroup = new Button(cnt().newGroup());
        newGroup.setAutoFit(true);
        newGroup.addClickHandler(new ClickHandler() {
            HandlerRegistration dataArrivedHR;
            @Override
            public void onClick(ClickEvent clickEvent) {
                sectionStack.expandSection(GroupsPanel.DETAILS_SECTION_ID);

                groupsGrid.deselectAllRecords();
                //listGrid.startEditingNew(Collections.singletonMap("schedule", scheduleKey));
                saveButton.setTitle(saveNewTitle);
                form.clearValues();
                //schedulesGrid.clear
                Map rec = new HashMap();
                rec.put("schedule", scheduleUser.getScheduleKey());
                if (!scheduleUser.isScheduleAdmin() && scheduleUser.getCurrentTeacherKey() != null) {
                    rec.put("teacher1Key", scheduleUser.getCurrentTeacherKey());
                }
                setupAccess(scheduleUser.getCurrentTeacherKey(), null, true);

                form.editNewRecord(rec);
                schedulesPanel.setVisible(false);
            }
        });

        gridButtons.addMember(newGroup);

        deleteGroup = new Button(cnt().removeButton());
        deleteGroup.setAutoFit(true);
        GUIUtil.addRemoveHandler(groupsGrid, deleteGroup, null);
        gridButtons.addMember(deleteGroup);


        setCalendarButton = new Button(cnt().setCalendar());
        setCalendarButton.setAutoFit(true);
        setCalendarButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                showSetCalendarDialog();
            }
        });
        gridButtons.addMember(setCalendarButton);

        if (scheduleUser.isScheduleAdmin()) {
            final Button getXmlButton = new Button(cnt().getXmlButton());
            getXmlButton.setAutoFit(true);
            getXmlButton.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(ClickEvent event) {
                    SchedulesListPanel.getXmlAction(scheduleUser.getScheduleKey(), scheduleUser.getInputLang(), getXmlButton);
                }
            });
            gridButtons.addMember(getXmlButton);


            final Button publishToSite = new Button(cnt().publishToSite());
            publishToSite.setAutoFit(true);
            publishToSite.addClickHandler(new ClickHandler() {
                @Override
                public void onClick(final ClickEvent event) {
                    SC.ask(cnt().areYouSure(), new BooleanCallback() {
                        @Override
                        public void execute(Boolean value) {
                            if (value) {
                                ScheduleServices.App.getInstance().postXmlToUrl(scheduleUser.getScheduleKey(), new MyAsyncCallback<Void>(publishToSite));
                            }
                        }
                    });
                }
            });
            gridButtons.addMember(publishToSite);
        }


        //mainPanel.addMember(detailsPanel);

        form.setUseAllDataSourceFields(true);

        listGridFields.clear();
        ArrayList<FormItem> formItems = new ArrayList<FormItem>();

        GUIUtil.setupFKField(listGridFields, formItems, "danceKey", "encodedKey", "name", "name", DancesDS.getInstance(scheduleUser), true, "danceName");
        GUIUtil.setupFKField(listGridFields, formItems, "levelKey", "encodedKey", "name", "name", LevelsDS.getInstance(scheduleUser), true, "levelName");
        GUIUtil.setupFKField(listGridFields, formItems, "teacher1Key", "encodedKey", "name", "name", TeachersDS.getInstance(scheduleUser), true, "teacher1Name");
        GUIUtil.setupFKField(listGridFields, formItems, "teacher2Key", "encodedKey", "name", "name", TeachersDS.getInstance(scheduleUser), true, "teacher2Name");
        GUIUtil.setupFKField(listGridFields, formItems, "locationKey", "encodedKey", "name", "name", LocationsDS.getInstance(scheduleUser), true, "locationName");
        GUIUtil.setupFKField(listGridFields, formItems, "calendarKey", "encodedKey", "name", "name", GCalendarDS.getInstance(scheduleUser), true, "gCalendarName");

        form.setFields(formItems.toArray(new FormItem[formItems.size()]));

        groupsGrid.setFields(listGridFields.toArray(new ListGridField[listGridFields.size()]));

        groupsListSection.addItem(gridPanel);
        groupDetailsSection.addItem(detailsPanel);

        this.addMember(this.sectionStack);

        groupsGrid.addSelectionChangedHandler(new SelectionChangedHandler() {
            @Override
            public void onSelectionChanged(SelectionEvent selectionEvent) {
                final Record selectedRecord = selectionEvent.getRecord();
                if (selectionEvent.getState() && sectionStack.sectionIsExpanded(GroupsPanel.DETAILS_SECTION_ID)) {
                    editGroup(selectedRecord);
                } else {
                    setupAccess(selectionEvent.getState() ? selectedRecord : null);                    
                }
            }
        });
        groupsGrid.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
            @Override
            public void onRecordDoubleClick(RecordDoubleClickEvent recordDoubleClickEvent) {
                sectionStack.expandSection(GroupsPanel.DETAILS_SECTION_ID);
                editGroup(recordDoubleClickEvent.getRecord());
            }
        });
        this.sectionStack.addSectionHeaderClickHandler(new SectionHeaderClickHandler() {
            @Override
            public void onSectionHeaderClick(SectionHeaderClickEvent event) {
                if (GroupsPanel.DETAILS_SECTION_ID.equals(event.getSection().getID()) && !sectionStack.sectionIsExpanded(GroupsPanel.DETAILS_SECTION_ID)) {
                    editGroup(groupsGrid.getSelectedRecord());
                }
            }
        });


        DynamicForm filterForm = new DynamicForm();


    }

    private void showSetCalendarDialog() {
        final ListGridRecord[] selection = groupsGrid.getSelection();
        if (selection == null || selection.length == 0) return;

        final Window window = new Window();
        window.setTitle(cnt().setCalendar());
        window.setWidth(500);
        window.setHeight(100);
        window.setIsModal(true);
        window.centerInPage();

        VLayout main = new VLayout();
        main.setPadding(10);

        final SelectItem selectItem = new SelectItem("calendarId", cnt().gcalendar());
        selectItem.setOptionDataSource(GCalendarDS.getInstance(scheduleUser));
        selectItem.setValueField("encodedKey");
        selectItem.setDisplayField("name");
        selectItem.setSortField("name");
        selectItem.setAllowEmptyValue(true);

        DynamicForm form = new DynamicForm();
        form.setFields(selectItem);

        main.addMember(form);

        Button okay = new Button(cnt().setCalendar());
        okay.setAutoFit(true);
        okay.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                final ListGridRecord selectedItem = selectItem.getSelectedRecord();
                String calendarKey = selectedItem != null ? selectedItem.getAttribute("encodedKey") : null;
                ArrayList<Record> records = new ArrayList<Record>(selection.length);
                for (ListGridRecord listGridRecord : selection) {
                    final Record record = new Record();
                    record.setAttribute("encodedKey", listGridRecord.getAttribute("encodedKey"));
                    record.setAttribute("calendarKey", calendarKey);
                    records.add(record);
                }

                GUIUtil.updateDataSynchroniously(groupsGrid, records.toArray(new Record[records.size()]));
                window.hide();
            }
        });

        Button close = new Button(cnt().closeButton());
        close.setAutoFit(true);
        close.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent clickEvent) {
                window.hide();
            }
        });

        HLayout buttons = new HLayout(5);
        buttons.addMember(okay);
        buttons.addMember(close);

        main.addMember(buttons);

        window.addItem(main);

        window.show();
    }

    public void editGroup(String groupKey) {
        for (ListGridRecord groupRecord : groupsGrid.getRecords()) {
            if (groupRecord.getAttribute("encodedKey").equals(groupKey)) {
                sectionStack.expandSection(DETAILS_SECTION_ID);
                final int row = groupsGrid.getRecordIndex(groupRecord);
                groupsGrid.deselectAllRecords();
                groupsGrid.scrollToRow(row);
                groupsGrid.selectRecord(row);
                editGroup(groupRecord);
                break;
            }
        }
    }

    private void editGroup(Record record) {
        setupAccess(record);

        form.clearValues();
        form.editRecord(record);

        saveButton.setTitle(cnt().saveChanges());

        schedulesPanel.setVisible(true);
        schedulesGrid.fetchData(new Criteria("group", record.getAttribute("encodedKey")));
    }

    private void setupAccess(Record record) {
        setupAccess(record != null ? record.getAttribute("teacher1Key") : null,
                record != null ? record.getAttribute("teacher2Key") : null,
                record != null);
    }

    private void setupAccess(String t1, String t2, boolean selected) {
        boolean canEdit = selected && (scheduleUser.isScheduleAdmin() || (scheduleUser.getCurrentTeacherKey() != null
                && (scheduleUser.getCurrentTeacherKey().equals(t1)
                 || scheduleUser.getCurrentTeacherKey().equals(t2))));
        newGroup.setDisabled(!scheduleUser.isScheduleAdmin() && scheduleUser.getCurrentTeacherKey() == null);
        saveButton.setDisabled(!canEdit);
        newSchedule.setDisabled(!canEdit);
        deleteSchedule.setDisabled(!canEdit);
        deleteGroup.setDisabled(!canEdit);
        schedulesGrid.setDisabled(!canEdit);
        form.setDisabled(!canEdit);
        setCalendarButton.setDisabled(!canEdit);
        if (canEdit && !scheduleUser.isScheduleAdmin()) {
            form.getItem("teacher1Key").setDisabled(scheduleUser.getCurrentTeacherKey().equals(t1));
            form.getItem("teacher2Key").setDisabled(scheduleUser.getCurrentTeacherKey().equals(t2) && !scheduleUser.getCurrentTeacherKey().equals(t1));
        }
    }

    public ListGrid getGroupsGrid() {
        return groupsGrid;
    }

    @Override
    public void invalidateData() {
        groupsGrid.invalidateCache();
        form.invalidateCache();
    }
}
